{
  This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
  the Free Software Foundation; version 2 of the License.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
}

// Copyright (c) 2010 2011 2012 - J. Aldo G. de Freitas Junior

{$mode objfpc}
{$H+}

Program
	XMLConsole;

Uses
	CMem,
	Classes,
	SysUtils,
	BaseException,
	Stacks,
	StringArray,
	StrUtils,
	ExprNodes,
	ExprLoader,
	Commands,
	Functions,
	XMLNodes,
	XMLTemplate,
	Nodes;{,
	ReadLine,
	History;}

Const
	ccConfigFile = 'config.xml';

Var
	gConfig : TDataBaseNode;
	gStack  : TVirtualMachineStack;
	gCommandLine : String;
	gCommandLoader : TCommandParser;
	gNodeFunctions : TNodeFunctions;
	gPrompt : String;

Procedure RunInteractive;
Begin
	Try
		Try
			gStack.Enter(0);
			gCommandLoader := TCommandParser.Create(Nil);
			gCommandLoader.DoLoadCommand('Implicit', '/scripts.|Name="autoexec"| execute');
			gCommandLoader.PropagateStack(gStack);
			gCommandLoader.Evaluate;
		Finally
			gStack.Leave(0);
			FreeAndNil(gCommandLoader);
		End;
	Except
		On E: EInterpreterException Do
			WriteLn(E.AsText);
		On E: Exception Do
			WriteLn(E.Message);
	End;
	{Using_History;}
	WriteLn('-----------------------------------------------------');
	WriteLn('       OOOO   PPP   EEEE  N   N  TTTTT  I  K  K      ');
	WriteLn('      O    O  P  P  E     NN  N    T    I  K K       ');
	WriteLn('      O    O  PPP   EE    N N N    T    I  KK        ');
	WriteLn('      O    O  P     E     N  NN    T    I  K K       ');
	WriteLn('       OOOO   P     EEEE  N   N    T    I  K  K      ');
	WriteLn('-----------------------------------------------------');
	WriteLn('         Copyright(C) - 2010 2011 2012               ');
	WriteLn('     Jorge Aldo Gomes de Freitas Junior et all       ');
	WriteLn('      Licensed under the terms of GPL License.       ');
	WriteLn('-----------------------------------------------------');
	WriteLn(' Type help for a list of available commands.         ');
	WriteLn;
	Repeat
		While Not gStack.Focused.IsCapableOf('focusable') do
			gStack.Focused := gStack.Focused.Owner As TXMLNode;
		gPrompt := gStack.Focused.IndexedName + '>';
		Write(gPrompt);
		ReadLn(gCommandLine);
		{
			* Tem algo errado com libreadline não gostei do resultado...
		
		gCommandLine := ReadLine.ReadLine(PChar(gPrompt));
		}
		Try
			Try
				gStack.Enter(0);
				gStack.ResultStr := '';
				gCommandLoader := TCommandParser.Create(Nil);
				gCommandLoader.DoLoadCommand('Command line', gCommandLine);
				gCommandLoader.PropagateStack(gStack);
				gCommandLoader.Evaluate;
				Write(gStack.ResultStr);
			Finally
				gStack.Leave(0);
				FreeAndNil(gCommandLoader);
			End;
		Except
			On E: EInterpreterException Do
				WriteLn(E.AsText);
			On E: Exception Do
				WriteLn(E.Message);
		End;
	Until Not gStack.Running;
End;

Procedure RunAsParser(Const aTemplate, aOutput : String);
Var
	lTemplate : TXMLTemplateRootNode;
	lFileStream : TFileStream;
	lBuffer : String;
	lStringStream : TStringStream;
Begin
	lTemplate := Nil;
	lFileStream := Nil;
	lStringStream := Nil;
	lBuffer := '';
	Try
		lTemplate := TXMLTemplateRootNode.Create(Nil);
		If FileExists(aOutput) Then
			DeleteFile(aOutput);
		lFileStream := TFileStream.Create(aOutput, fmCreate);
		lTemplate.LoadFromFile(aTemplate);
		lTemplate.PropagateStack(gStack);
		lBuffer := lTemplate.Emit;
		lBuffer := StringReplace(lBuffer, ccNewLine, #13, [ rfReplaceAll, rfIgnoreCase ]);
		lBuffer := StringReplace(lBuffer, ccSpace, ' ', [ rfReplaceAll, rfIgnoreCase ]);
		lBuffer := StringReplace(lBuffer, ccTab, #09, [ rfReplaceAll, rfIgnoreCase ]);
		lBuffer := AdjustLineBreaks(lBuffer);
		lBuffer := DelSpace1(lBuffer);
		lStringStream := TStringStream.Create(lBuffer);
		lStringStream.Seek(0, soFromBeginning);
		lFileStream.CopyFrom(lStringStream, lStringStream.Size);
	Finally
		FreeAndNil(lTemplate);
		FreeAndNil(lFileStream);
		FreeAndNil(lStringStream);
	End;
End;

Begin
	gConfig := TDataBaseNode.Create(Nil);
	gStack := TVirtualMachineStack.Create;
	gNodeFunctions := TNodeFunctions.Create;
	Try
		Try
			gConfig.LoadFromFile(ccConfigFile);
		Except
			On E: EInterpreterException Do
				WriteLn(E.AsText);
			On E: Exception Do
				WriteLn(E.Message);
		End;			
		gStack.RegisterFunctor(gNodeFunctions);
		gNodeFunctions.Stack := gStack;
		gStack.Focused := gConfig;
		gStack.Running := True;
		If ParamCount = 0 Then
			RunInteractive
		Else If ParamCount = 2 Then
			RunAsParser(ParamStr(1), ParamStr(2))
		Else
			Raise Exception.Create('You must provide correct parameters or run as interactive.');
	Finally
		FreeAndNil(gNodeFunctions);
		FreeAndNil(gConfig);
		FreeAndNil(gStack);
	End;
End.
